#pragma once
#include "refc_ptr.h"
#include "widget.h"
#include "window.h"
#include "render_control_impl_base.h"

namespace krryn{
namespace gui{
	// A class for managing rendering control implementations
	// every rendering api (eg. every class that inherits from
	// renderer) should register here to provide a 
	// render_control_impl_base derivative.
	//
	// This part isn't handled by the create_widget_base function
	// because the api we're using might have to be specified
	// at run time (eg. read from a configuration file).
	//
	// Platform specific (eg. windows / os x) api derivatives
	// (render_control_opengl_win32_impl for example) should 
	// be created using create_widget_base. This means you'll 
	// probably end up doing something as:
	//
	// <code>
	// render_control_impl_manager::instance()
	//	.register_control_imp("opengl", 
	//		create_widget_base<render_control_opengl_impl_base>());
	// </code>
	//
	// This would result in create_widget returning the platform
	// specific instance of render_control_opengl_impl_base.
	class render_control_impl_manager{
	public:
		static render_control_impl_manager &instance();

		render_control_impl_base *create_render_control_impl(const std::string &a_Api){
			if(m_Implementations[a_Api]){
				return m_Implementations[a_Api]->create();
			}

			throw std::runtime_error("Invalid rendering api specified, '" + a_Api + "'");
		}

		void register_control_imp(const std::string &a_Api, render_control_impl_base *a_Impl){
			if(!m_Implementations[a_Api]){
				m_Implementations[a_Api] = a_Impl;
			}
		}
	private:
		std::map<std::string, render_control_impl_base*> m_Implementations;
	};

	class render_control_initializer;
	class render_control : public widget{
	public:
		typedef render_control_impl_base impl;
		typedef render_control_initializer with;

		render_control(const with &a_Initializer);

		void swap_buffers(){
			m_Pimpl->swap_buffers();
		}

		view::renderer *get_renderer(){
			return m_Pimpl->get_renderer();
		}

		virtual void* handle(){
			return m_Pimpl->handle();
		}
	private:
		render_control_impl_base *m_Pimpl;
	};

	class render_control_initializer : public widget_initializer<render_control_initializer>{
	public:
		render_control_initializer() 
			: m_Fullscreen(false), m_BitsPerPixel(32), m_Api("<unknown-api>") {}

		render_control_initializer &fullscreen(bool a_Fullscreen){
			m_Fullscreen = a_Fullscreen;
			return *this;
		}

		render_control_initializer &bits_per_pixel(unsigned int a_BitsPerPixel){
			m_BitsPerPixel = a_BitsPerPixel;
			return *this;
		}

		render_control_initializer &vsync(bool a_Enabled){
			m_Vsync = a_Enabled;
			return *this;
		}

		render_control_initializer &api(const std::string &a_Api){
			m_Api = a_Api;
			return *this;
		}

		render_control* create(){
			if(get_parent() == 0){
				// create a default window if we have none
				parent(window::with()
					.width(get_width())
					.top(get_top())
					.left(get_left())
					.height(get_height())
					.create());

				// reset the top and left position because it doesn't make sense
				// to use it for both the window and this control
				top(0);
				left(0);
			}

			return new render_control(*this);
		}

		unsigned int m_BitsPerPixel;
		bool m_Fullscreen;
		std::string m_Api;
		bool m_Vsync;
	};
}
}